/// Coder: Jose Ricardo Mello Viana - 2008
/// Bugs? e-mail me: zezim.ricardo@gmail.com

/*
 * application.h
 *
 *  Created on: 20/08/2008
 *      Author: zezim
 */

#ifndef APPLICATION_H_
#define APPLICATION_H_

#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <set>
#include <cassert>
#include <cmath>

#include "glslKernel.h"
#include "geomTypes/geomTypes.h"

#include "fboClass/framebufferObject.h"
#include "fboClass/renderbuffer.h"
#include "fboClass/glErrorUtil.h"

#include "paintCursor.h"
#include "colorBuffer.h"
#include "colorInterface.h"
#include "texObj.h"

#include <GL/glut.h>

using namespace std;

typedef float              Number;
typedef Point<2, Number>   Point2;
typedef Point<4, Number>   Point4;
typedef Vector<3, Number>  Vector3;

class Application {
public:
   /// Class constructor
   /// @param w given window width
   /// @param h given window heigth
   Application(int w, int h);

   /// Class destructor
   virtual ~Application();

   /// General initializations
   void init();

   /// Draw model, cursor, color buffer and texture(s)
   void draw();

   /// Gets normal buffer from model
   void getNormalBuffer();

   /// Gets point IDs from model
   void getPointIDsBuffer();

   /// Click on mouse left button
   /// @param x given x mouse coordinate
   /// @param y given y mouse coordinate
   void mouseLeft(int x, int y);

   /// Click on mouse middle button
   /// @param x given x mouse coordinate
   /// @param y given y mouse coordinate
   void mouseMiddle(int x, int y);

   /// Click on mouse right button
   /// @param x given x mouse coordinate
   /// @param y given y mouse coordinate
   void mouseRight(int x, int y);

   /// Unclick on mouse button
   /// @param x given x mouse coordinate
   /// @param y given y mouse coordinate
   void mouseUp(int x, int y);

   /// Update internal parameters who depends of mouse position
   /// @param x given x mouse coordinate
   /// @param y given y mouse coordinate
   void updateMouseCoords(int x, int y);

   /// Build mesh structure from file
   /// @param filename given name of file
   void buildMesh(string filename);

   /// Read the OFF model
   /// @param filename the file name
   /// @return true if it succeed
   bool readOFFfile(const char *filename);

   /// Render a string
   /// @param x given x position
   /// @param y given y position
   /// @param z given z position
   /// @param font given font to draw text
   /// @param string given message from renderization
   void renderBitmapString(float x, float y, float z, void *font, const char *string);

   /// Renders info about the mesh
   void renderInfo(bool isT);

   /// Gets a cursor
   /// @return given cursor
   PaintCursor* getCursor() { return cursor; };

   /// Gets a color buffer
   /// @return given buffer
   ColorBuffer* getBuffer() { return buffer; };

   void showAtlas() { if (!show_atlas) mountAtlas(); show_atlas = !show_atlas; };

   void mountAtlas();

   void alternShowInterface() { showi = !showi; interface->setVisible(showi); };

   /// temporary methods from tests
   void invertDrawN() { dn = !dn; };
   void invertDrawP() { dp = !dp; };
   void yDrawB() { drawb = true; texAt = (texAt + 1) % texObjs.size();};
   void nDrawB() { drawb = false; texAt = -1;};
   void invDrawCB() {drawcb = !drawcb; };
   void invertShowMapOnAtlas() { show_map_on_atlas = !show_map_on_atlas; };

   float distancia(Point4 a, Point4 b);

private:
   int texAt;
   bool drawcb;
   bool initBuffer;
   bool show_atlas;
   bool show_map_on_atlas;
   Point2i mini, maxi, nmini, nmaxi;

   int medial_edge;

   /// Paint Cursor
   PaintCursor          *cursor;

   /// Color Buffer
   ColorBuffer          *buffer;

   /// Color Interface
   ColorInterface       *interface;

   /// Textures and Atlas
   vector<TexObj*>      texObjs, atlas;
   int 					size_atlas;

   /// Show or not show color interface
   bool                 showi;

   /// Normal Buffer
   GLfloat*             nb;

   /// Point IDs buffer
   GLfloat*             pb;

   /// Texture reading from buffer
   GLfloat*            tb;

   /// Shader variables
   glslKernel*          shader_normal;
   glslKernel*          shader_basic;
   glslKernel*          shader_point_ids;
   glslKernel*          shader_point_ids2;
   glslKernel*          shader_tex_coord;

   /// Render to texture variables
   FramebufferObject    fbo;
   Renderbuffer         rb;
   GLuint               textures[4], test;

   /// Illumination variables
   Vector3              ambient,
                        diffuse,
                        specular;
   GLfloat              shineness;

   /// Mesh variables
   string               meshfile;
   int                  nvertices,
                        nfaces;
   vector<Point4>       mesh_pos, mesh_p;
   vector<Vector3>      mesh_normals;
   vector<unsigned>     mesh_faces;
   vector<int>    		faces_tex;
   vector< set<int> >   facespervertex;

   GLuint               vbo, vbo2; /// vertex buffer object id
   GLuint               nbo; /// normal buffer object id
   GLuint               ebo; /// element buffer object id

   /// Window size variables
   int                  winw,
                        winh;

   /// Rotation variables
   float                rotate_x,
                        rotate_y;

   /// Mouse position and button pressed variables
   int                  mouse_old_x,
                        mouse_old_y;
   int                  buttonpressed;

   /// Control variables
   bool                 dn, dp,
                        drawb,
                        updateBuffers,
                        updateBuffersNow,
                        updateTextureNow,
                        genTex;

   /// Time info variables
   float                cfps;
   time_t               start,
                        end;
   unsigned             frame;

   /// Info variables
   void                 *font,
                        *fontsmall;
   string               snvertices,
                        snfaces,
                        snconstraints,
                        fps;
};

//inline bool operator<(const Point3 &p1, const Point3 &p2) {
//   if ((p2[0] > p1[0]) ||
//      (p2[0] == p1[0] && p2[1] > p1[1]) ||
//      (p2[0] == p1[0] && p2[1] == p1[1]  && p2[2] > p1[2])) {
//      return true;
//   } else {
//      return false;
//   }
//}

inline bool operator<(const Point4 &p1, const Point4 &p2) {
   if ((p2[0] > p1[0]) ||
      (p2[0] == p1[0] && p2[1] > p1[1]) ||
      (p2[0] == p1[0] && p2[1] == p1[1] && p2[2] > p1[2]) ||
      (p2[0] == p1[0] && p2[1] == p1[1] && p2[2] == p1[2] && p2[3] > p1[3])) {
      return true;
   } else {
      return false;
   }
}

#endif /* APPLICATION_H_ */
